
export type EventType = string;
export type EventHandler<T = any> = (event?: any) => void;

type HandlerMap = Record<EventType, EventHandler[]>

export default class Emitter{

    all: HandlerMap = {};

    on<T = any>(type: EventType, handler: EventHandler<T>) {
        const handlers = this.all[type];
        
        if (!handlers){
            this.all[type] = [handler];
        } else {
            handlers.push(handler);
        }
    }

    /**
     * remove event handler with type.
     * @param type 
     * @param handler 
     */
    off<T = any>(type: EventType, handler?: EventHandler<T>) {
        
        if (!handler) {
            delete this.all[type];
        } else {
            const handlers = this.all[type];
            handlers && handlers.splice(handlers.indexOf(handler), 1);
        }
    }

    /**
     * fire an event.
     * @param type 
     * @param evt 
     */
    emit<T = any>(type: EventType, evt?: T) {
        ((this.all[type] || []) as EventHandler[]).slice().map(handler => handler(evt))
    }

    /**
     * remove all listeners.
     */
    clear() {
        for (let type in this.all) {
            if (this.all.hasOwnProperty(type)) {
                delete this.all[type];
            }
        }
    }

}